diff options
| author | dujinkim <dujin.kim@dtsolution.co.kr> | 2025-09-04 08:31:31 +0000 |
|---|---|---|
| committer | dujinkim <dujin.kim@dtsolution.co.kr> | 2025-09-04 08:31:31 +0000 |
| commit | b67e36df49f067cbd5ba899f9fbcc755f38d4b4f (patch) | |
| tree | 5a71c5960f90d988cd509e3ef26bff497a277661 /app/[lng]/admin/edp-progress-debug/page.tsx | |
| parent | b7f54b06c1ef9e619f5358fb0a5caad9703c8905 (diff) | |
(대표님, 최겸, 임수민) 작업사항 커밋
Diffstat (limited to 'app/[lng]/admin/edp-progress-debug/page.tsx')
| -rw-r--r-- | app/[lng]/admin/edp-progress-debug/page.tsx | 210 |
1 files changed, 210 insertions, 0 deletions
diff --git a/app/[lng]/admin/edp-progress-debug/page.tsx b/app/[lng]/admin/edp-progress-debug/page.tsx new file mode 100644 index 00000000..ebaa07a2 --- /dev/null +++ b/app/[lng]/admin/edp-progress-debug/page.tsx @@ -0,0 +1,210 @@ +"use client"; + +import React from 'react'; +import { Button } from '@/components/ui/button'; +import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card'; +import { Input } from '@/components/ui/input'; +import { Label } from '@/components/ui/label'; +import { Badge } from '@/components/ui/badge'; +import { ScrollArea } from '@/components/ui/scroll-area'; +import { debugVendorFieldCalculation } from '@/lib/forms/vendor-completion-stats'; +import { Loader, Search, FileText, Tag, CheckCircle, XCircle } from 'lucide-react'; +import { toast } from 'sonner'; + +export default function DebugVendorFieldsPage() { + const [loading, setLoading] = React.useState(false); + const [vendorId, setVendorId] = React.useState('1'); + const [debugData, setDebugData] = React.useState<any>(null); + + const handleDebug = async () => { + setLoading(true); + setDebugData(null); + + try { + const result = await debugVendorFieldCalculation(Number(vendorId)); + setDebugData(result); + + if (result) { + toast.success(`${result.vendorName}의 필드 계산 디버그 완료`); + } else { + toast.warning('벤더 데이터가 없습니다'); + } + } catch (error) { + console.error('Error debugging vendor fields:', error); + toast.error(`디버그 실패: ${error instanceof Error ? error.message : '알 수 없는 오류'}`); + } finally { + setLoading(false); + } + }; + + const renderFieldDetails = (fieldDetails: any[]) => ( + <div className="space-y-1"> + {fieldDetails.map((field, index) => ( + <div key={index} className="flex items-center gap-2 text-xs"> + <span className="font-mono bg-muted px-1 rounded">{field.fieldKey}</span> + <span className="text-muted-foreground">=</span> + <span className="font-mono">{String(field.fieldValue ?? 'null')}</span> + {field.isEmpty ? ( + <XCircle className="h-3 w-3 text-red-500" /> + ) : ( + <CheckCircle className="h-3 w-3 text-green-500" /> + )} + </div> + ))} + </div> + ); + + return ( + <div className="container mx-auto p-6 space-y-6"> + <div className="flex items-center gap-2 mb-6"> + <Search className="h-6 w-6" /> + <h1 className="text-3xl font-bold">벤더 필드 계산 디버그</h1> + </div> + + {/* Input */} + <Card> + <CardHeader> + <CardTitle>벤더 ID 입력</CardTitle> + </CardHeader> + <CardContent> + <div className="flex gap-4"> + <div className="space-y-2"> + <Label htmlFor="vendorId">Vendor ID</Label> + <Input + id="vendorId" + value={vendorId} + onChange={(e) => setVendorId(e.target.value)} + placeholder="1" + type="number" + /> + </div> + <div className="flex items-end"> + <Button onClick={handleDebug} disabled={loading}> + {loading ? <Loader className="h-4 w-4 animate-spin mr-2" /> : <Search className="h-4 w-4 mr-2" />} + 디버그 실행 + </Button> + </div> + </div> + </CardContent> + </Card> + + {/* Results */} + {debugData && ( + <div className="space-y-4"> + {/* Summary */} + <Card> + <CardHeader> + <CardTitle className="flex items-center gap-2"> + <FileText className="h-5 w-5" /> + {debugData.vendorName} - 전체 요약 + </CardTitle> + </CardHeader> + <CardContent> + <div className="grid grid-cols-2 md:grid-cols-4 gap-4"> + <div className="text-center"> + <div className="text-2xl font-bold text-blue-600"> + {debugData.debugInfo.grandTotal.totalRequiredFields} + </div> + <p className="text-sm text-muted-foreground">전체 필드</p> + </div> + <div className="text-center"> + <div className="text-2xl font-bold text-green-600"> + {debugData.debugInfo.grandTotal.totalFilledFields} + </div> + <p className="text-sm text-muted-foreground">입력 필드</p> + </div> + <div className="text-center"> + <div className="text-2xl font-bold text-red-600"> + {debugData.debugInfo.grandTotal.totalEmptyFields} + </div> + <p className="text-sm text-muted-foreground">빈 필드</p> + </div> + <div className="text-center"> + <div className="text-2xl font-bold text-purple-600"> + {debugData.debugInfo.grandTotal.completionPercentage}% + </div> + <p className="text-sm text-muted-foreground">완성도</p> + </div> + </div> + </CardContent> + </Card> + + {/* Detailed Breakdown */} + <Card> + <CardHeader> + <CardTitle>상세 분석</CardTitle> + </CardHeader> + <CardContent> + <ScrollArea className="h-96"> + <div className="space-y-4"> + {debugData.debugInfo.contracts.map((contract: any, contractIndex: number) => ( + <div key={contractIndex} className="border rounded-lg p-4"> + <div className="flex items-center gap-2 mb-3"> + <Tag className="h-4 w-4" /> + <span className="font-semibold"> + 계약 {contract.contractId} - {contract.projectName} + </span> + <Badge variant="outline"> + 전체: {contract.totalRequiredFields} | 입력: {contract.totalFilledFields} + </Badge> + </div> + + <div className="space-y-3 ml-4"> + {contract.forms.map((form: any, formIndex: number) => ( + <div key={formIndex} className="border-l-2 border-muted pl-4"> + <div className="flex items-center gap-2 mb-2"> + <FileText className="h-3 w-3" /> + <span className="font-medium">{form.formName} ({form.formCode})</span> + <Badge variant="secondary" className="text-xs"> + 전체: {form.totalRequiredFields} | 입력: {form.totalFilledFields} + </Badge> + </div> + + <div className="space-y-2 ml-4"> + {form.tags.map((tag: any, tagIndex: number) => ( + <div key={tagIndex} className="bg-muted/50 rounded p-2"> + <div className="flex items-center gap-2 mb-1"> + <Tag className="h-3 w-3" /> + <span className="font-mono text-sm">{tag.tagNo}</span> + <Badge variant="outline" className="text-xs"> + 전체: {tag.requiredFieldsCount} | 입력: {tag.filledFieldsCount} + </Badge> + </div> + + <div className="ml-4"> + <div className="text-xs text-muted-foreground mb-1"> + 편집 가능한 필드: {tag.editableFields.join(', ')} + </div> + {renderFieldDetails(tag.fieldDetails)} + </div> + </div> + ))} + </div> + </div> + ))} + </div> + </div> + ))} + </div> + </ScrollArea> + </CardContent> + </Card> + + {/* Raw Data */} + <Card> + <CardHeader> + <CardTitle>원시 데이터 (JSON)</CardTitle> + </CardHeader> + <CardContent> + <ScrollArea className="h-64"> + <pre className="text-xs bg-muted p-4 rounded overflow-auto"> + {JSON.stringify(debugData, null, 2)} + </pre> + </ScrollArea> + </CardContent> + </Card> + </div> + )} + </div> + ); +}
\ No newline at end of file |
